<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 File Descriptors
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora165.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora167.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> File Descriptors</H2>
In chapter <A HREF="book-ora027.html#sec-PI-IO">3</A> we have seen functions from the standard
module <TT>Pervasives</TT>. These functions allow us to access files via input&nbsp;/
output channels. There is also a lower-level way to access files,
using their descriptors.<BR>
<BR>
A file descriptor is an abstract value of type <TT>Unix.file_descr</TT>,
containing information necessary to use a file: a pointer to the file,
the access rights, the access modes (read or write), the current position
in the file, etc.<BR>
<BR>
<A NAME="@fonctions405"></A>
<A NAME="@fonctions406"></A>
<A NAME="@fonctions407"></A><BR>
<BR>
Three descriptors are predefined. They correspond to standard input,
standard output, and standard error.<BR>
<BR>


<PRE><BR># <TT>(</TT><CODE> </CODE>Unix.stdin<CODE> </CODE><CODE>,</CODE><CODE> </CODE>Unix.stdout<CODE> </CODE><CODE>,</CODE><CODE> </CODE>Unix.stderr<CODE> </CODE><TT>)</TT><CODE> </CODE>;;<BR><CODE>- : Unix.file_descr * Unix.file_descr * Unix.file_descr =</CODE><BR><CODE>&lt;abstr&gt;, &lt;abstr&gt;, &lt;abstr&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Be careful not to confuse them with the corresponding input / output
channels:<BR>
<BR>


<PRE><BR># <TT>(</TT><CODE> </CODE>Pervasives.stdin<CODE> </CODE><CODE>,</CODE><CODE> </CODE>Pervasives.stdout<CODE> </CODE><CODE>,</CODE><CODE> </CODE>Pervasives.stderr<CODE> </CODE><TT>)</TT><CODE> </CODE>;;<BR><CODE>- : in_channel * out_channel * out_channel = &lt;abstr&gt;, &lt;abstr&gt;, &lt;abstr&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The conversion functions between channels and file descriptors
are described at page <A HREF="book-ora166.html#sec-io-convert">??</A>.<BR>
<BR>

<H5> File Access Rights.</H5> 
Under Unix each file has an associated owner and group.
The rights to read, write and execute are attached
to each file according to three categories of users:
the owner of a file, the members of the file's group<A NAME="text40" HREF="book-ora172.html#note40"><SUP><FONT SIZE=2>1</FONT></SUP></A> and all other users.<BR>
<BR>
The access rights of a file are represented by 9 bits divided
into three groups of three bits each. The first group represents the
rights of the owner, the second the rights of the members of the
owner's group, and the last the rights of all other users.
In each group of three bits, the first bit represents the right to
read, the second bit the right to write and the third bit the right
to execute.
It is common to abbreviate these three rights by the letters
<TT>r</TT>, <TT>w</TT> and <TT>x</TT>. The absence of the rights is
represented in each case by a dash (<TT>-</TT>).
For exampple, the right to read for all and the right to write
only for the owner is written as <CODE>rw-r--r--</CODE>. This corresponds
to the integer <EM>420</EM> (which is the binary number
<EM>0b110100100</EM>). Frequently the more comfortable octal notation
<EM>0o644</EM> is used. These file access rights are not used
under Windows.<BR>
<BR>
REVIEWER'S QUESTION: IS THIS STILL TRUE UNDER WIN2K?<BR>
<BR>
<A NAME="toc244"></A>
<H3> File Manipulation</H3>
<H5> Opening a file.</H5>
<A NAME="@fonctions408"></A>
<A NAME="@fonctions409"></A>Opening a file associates the file to a file descriptor.
Depending on the intended use of the file there are
several modes to open a file. Each mode corresponds to
a value of type <I>open_flag</I> described by figure
<A HREF="book-ora166.html#fig-open_flag">18.2</A>.
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1>
<TR><TD  ALIGN=left NOWRAP><TT>O_RDONLY</TT></TD>
<TD  ALIGN=left NOWRAP>read only</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>O_WRONLY</TT></TD>
<TD  ALIGN=left NOWRAP>write only</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>O_RDWR</TT></TD>
<TD  ALIGN=left NOWRAP>reading and writing</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>O_NONBLOCK</TT></TD>
<TD  ALIGN=left NOWRAP>non-blocking opening</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>O_APPEND</TT></TD>
<TD  ALIGN=left NOWRAP>appending at the end of the file</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>O_CREAT</TT></TD>
<TD  ALIGN=left NOWRAP>create a new file if it does not exist</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>O_TRUNC</TT></TD>
<TD  ALIGN=left NOWRAP>set the file to 0 if it exists</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>O_EXCL</TT></TD>
<TD  ALIGN=left NOWRAP>chancel, if the file already exists</TD>
</TR></TABLE>
<BR>
<DIV ALIGN=center>Figure 18.2: Values of type <I>open_flag</I>.</DIV><BR>

<A NAME="fig-open_flag"></A>
</DIV>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>These modes can be combined. In consequence, the function
<TT>openfile</TT> takes as argument a list of values of type
<I>open_flag</I>.


<PRE><BR># Unix.openfile<CODE> </CODE>;;<CODE> </CODE><BR><CODE>- : string -&gt; Unix.open_flag list -&gt; Unix.file_perm -&gt; Unix.file_descr =</CODE><BR><CODE>&lt;fun&gt;</CODE><BR>

</PRE>

The first argument is the name of the file. The last is an
integer<A NAME="text41" HREF="book-ora172.html#note41"><SUP><FONT SIZE=2>2</FONT></SUP></A> coding the rights to attach to the file
in the case of creation.<BR>
<BR>
Here is an example of how to open a file for reading, or to create it with
the rights <CODE>rw-r--r--</CODE> if it does not exist:


<PRE><BR># <B>let</B><CODE> </CODE>file<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.openfile<CODE> </CODE><CODE>"test.dat"</CODE><CODE> </CODE><CODE>[</CODE>Unix<CODE>.</CODE>O_RDWR;<CODE> </CODE>Unix<CODE>.</CODE>O_CREAT<CODE>]</CODE><CODE> </CODE><CODE>0</CODE>o644<CODE> </CODE>;;<BR><CODE>val file : Unix.file_descr = &lt;abstr&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Closing a file.</H5>
<A NAME="@fonctions410"></A>
The function <TT>Unix.close</TT> closes a file. It is applied
to the descriptor of the file to close.


<PRE><BR># Unix.close<CODE> </CODE>;;<BR><CODE>- : Unix.file_descr -&gt; unit = &lt;fun&gt;</CODE><BR># Unix.close<CODE> </CODE>file<CODE> </CODE>;;<BR><CODE>- : unit = ()</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Redirecting file descriptors.</H5>
<A NAME="@fonctions411"></A>
<A NAME="@fonctions412"></A>
It is possible to attach several file descriptors to one input / output.
If there is only one file descriptor available and another one
is desired we can use:


<PRE><BR># Unix.dup<CODE> </CODE>;;<BR><CODE>- : Unix.file_descr -&gt; Unix.file_descr = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
If we have two file descriptors and we want to assign to the second the
input / output of the first, we can use the function:


<PRE><BR># Unix.dup2<CODE> </CODE>;;<BR><CODE>- : Unix.file_descr -&gt; Unix.file_descr -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
For example, the error output can be directed to a file
in the following way:


<PRE><BR># <B>let</B><CODE> </CODE>error_output<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.openfile<CODE> </CODE><CODE>"err.log"</CODE><CODE> </CODE><CODE>[</CODE>Unix<CODE>.</CODE>O_WRONLY;Unix<CODE>.</CODE>O_CREAT<CODE>]</CODE><CODE> </CODE><CODE>0</CODE>o644<CODE> </CODE>;;<BR><CODE>val error_output : Unix.file_descr = &lt;abstr&gt;</CODE><BR># Unix.dup2<CODE> </CODE>Unix.stderr<CODE> </CODE>error_output<CODE> </CODE>;;<BR><CODE>- : unit = ()</CODE><BR>

</PRE>

Data written to the standard error output will now be directed to the file
<TT>err.log</TT>. <BR>
<BR>
<A NAME="toc245"></A>
<H3> Input / Output on Files</H3>
<A NAME="@fonctions413"></A>
<A NAME="@fonctions414"></A>
The functions to read and to write to a file
<TT>Unix.read</TT> and <TT>Unix.write</TT> use a character string
as medium between the file and the Objective CAML program.


<PRE><BR># Unix.read<CODE> </CODE>;;<BR><CODE>- : Unix.file_descr -&gt; string -&gt; int -&gt; int -&gt; int = &lt;fun&gt;</CODE><BR># Unix.write<CODE> </CODE>;;<BR><CODE>- : Unix.file_descr -&gt; string -&gt; int -&gt; int -&gt; int = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
In addition to the file descriptor and the string the functions take
two integers as arguments. One is the index of the first character
and the other the number of characters to read or to write.
The returned integer is the number of characters effectively
read or written.


<PRE><BR># <B>let</B><CODE> </CODE>mode<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>[</CODE>Unix<CODE>.</CODE>O_WRONLY;Unix<CODE>.</CODE>O_CREAT;Unix<CODE>.</CODE>O_TRUNC<CODE>]</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>fl<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.openfile<CODE> </CODE><CODE>"file"</CODE><CODE> </CODE>mode<CODE> </CODE><CODE>0</CODE>o644<CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>str<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"012345678901234565789"</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.write<CODE> </CODE>fl<CODE> </CODE>str<CODE> </CODE><CODE>4</CODE><CODE> </CODE><CODE>5</CODE><CODE> </CODE><BR><CODE> </CODE><B>in</B><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"We wrote %s to the file\n"</CODE><CODE> </CODE><TT>(</TT>String.sub<CODE> </CODE>str<CODE> </CODE><CODE>4</CODE><CODE> </CODE>n<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.close<CODE> </CODE>fl<CODE> </CODE>;;<BR><CODE>We wrote 45678 to the file</CODE><BR><CODE>- : unit = ()</CODE><BR>

</PRE>
<BR>
<BR>
Reading a file works the same way:


<PRE><BR># <B>let</B><CODE> </CODE>fl<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.openfile<CODE> </CODE><CODE>"file"</CODE><CODE> </CODE><CODE>[</CODE>Unix<CODE>.</CODE>O_RDONLY<CODE>]</CODE><CODE> </CODE><CODE>0</CODE>o644<CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>str<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.make<CODE> </CODE><CODE>2</CODE><CODE>0</CODE><CODE> </CODE><CODE>'.'</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.read<CODE> </CODE>fl<CODE> </CODE>str<CODE> </CODE><CODE>2</CODE><CODE> </CODE><CODE>1</CODE><CODE>0</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"We read  %d characters"</CODE><CODE> </CODE>n;<BR><CODE> </CODE><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>" and got the string %s\n"</CODE><CODE> </CODE>str;<BR><CODE> </CODE><CODE> </CODE>Unix.close<CODE> </CODE>fl<CODE> </CODE>;;<BR><CODE>We read  5 characters and got the string ..45678.............</CODE><BR><CODE>- : unit = ()</CODE><BR>

</PRE>
<BR>
<BR>
<A NAME="@fonctions415"></A>
<A NAME="@fonctions416"></A>
Access to a file always takes place at the current position
of its descriptor. The current position can be modified by the
function:


<PRE><BR># Unix.lseek<CODE> </CODE>;;<BR><CODE>- : Unix.file_descr -&gt; int -&gt; Unix.seek_command -&gt; int = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The first argument is the file descriptor. The second specifies the
displacement as number of characters. The third argument is of
type <I>Unix.seek_command</I> and indicates the origin of the
displacement. The third argument may take one of three posssible
values:
<UL>
<LI>
 <TT>SEEK_SET</TT>: relative to the beginning of the file,

<LI> <TT>SEEK_CUR</TT>: relative to the current position,

<LI> <TT>SEEK_END</TT>: relative to the end of the file. 
</UL>
A function call with an erronous position will either raise
an exception or return a value equal to 0.<BR>
<BR>

<H5> Input / output channels.</H5><A NAME="par-channel"></A>
<A NAME="sec-io-convert"></A>
<A NAME="@fonctions417"></A>
<A NAME="@fonctions418"></A> 
<A NAME="@fonctions419"></A>
<A NAME="@fonctions420"></A> 
<A NAME="@fonctions421"></A> 
<A NAME="@fonctions422"></A> 
The <TT>Unix</TT> module provides conversion functions between
file descriptors and the input / output channels of module
<TT>Pervasives</TT>:


<PRE><BR># Unix.in_channel_of_descr<CODE> </CODE><CODE> </CODE>;;<BR><CODE>- : Unix.file_descr -&gt; in_channel = &lt;fun&gt;</CODE><BR># Unix.out_channel_of_descr<CODE> </CODE>;;<BR><CODE>- : Unix.file_descr -&gt; out_channel = &lt;fun&gt;</CODE><BR># Unix.descr_of_in_channel<CODE> </CODE><CODE> </CODE>;;<BR><CODE>- : in_channel -&gt; Unix.file_descr = &lt;fun&gt;</CODE><BR># Unix.descr_of_out_channel<CODE> </CODE>;;<BR><CODE>- : out_channel -&gt; Unix.file_descr = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
It is necessary to indicate whether the input / output channels
obtained by the conversion transfer binary data or character data.


<PRE><BR># set_binary_mode_in<CODE> </CODE>;;<BR><CODE>- : in_channel -&gt; bool -&gt; unit = &lt;fun&gt;</CODE><BR># set_binary_mode_out<CODE> </CODE>;;<BR><CODE>- : out_channel -&gt; bool -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
In the following example we create a file by using the functions
of module <TT>Unix</TT>. We read using the opening function of
module <TT>Unix</TT> and the higher-level input function
<TT>input_line</TT>.


<PRE><BR># <B>let</B><CODE> </CODE>mode<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>[</CODE>Unix<CODE>.</CODE>O_WRONLY;Unix<CODE>.</CODE>O_CREAT;Unix<CODE>.</CODE>O_TRUNC<CODE>]</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>f<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.openfile<CODE> </CODE><CODE>"file"</CODE><CODE> </CODE>mode<CODE> </CODE><CODE>0</CODE>o666<CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"0123456789\n0123456789\n"</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.write<CODE> </CODE>f<CODE> </CODE>s<CODE> </CODE><CODE>0</CODE><CODE> </CODE><TT>(</TT>String.length<CODE> </CODE>s<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><B>in</B><CODE> </CODE>Unix.close<CODE> </CODE>f<CODE> </CODE>;;<BR><CODE>- : unit = ()</CODE><BR># <B>let</B><CODE> </CODE>f<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.openfile<CODE> </CODE><CODE>"file"</CODE><CODE> </CODE><CODE>[</CODE>Unix<CODE>.</CODE>O_RDONLY;Unix<CODE>.</CODE>O_NONBLOCK<CODE>]</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.in_channel_of_descr<CODE> </CODE>f<CODE> </CODE><B>in</B><BR><CODE> </CODE><B>let</B><CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE>input_line<CODE> </CODE>c<CODE> </CODE><BR><CODE> </CODE><B>in</B><CODE> </CODE>print_string<CODE> </CODE>s<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>close_in<CODE> </CODE>c<CODE> </CODE>;;<BR><CODE>0123456789- : unit = ()</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Availability.</H5> 
A program may have to work with multiple inputs and outputs.
Data may not always be available on a given channel, and the program
cannot afford to wait for one channel to be available while ignoring
the others. The following function lets you determine which of a given list
of inputs/outputs is available for use at a given time:


<PRE><BR># Unix.select<CODE> </CODE>;;<BR><CODE>- : Unix.file_descr list -&gt;</CODE><BR><CODE>    Unix.file_descr list -&gt;</CODE><BR><CODE>    Unix.file_descr list -&gt;</CODE><BR><CODE>    float -&gt;</CODE><BR><CODE>    Unix.file_descr list * Unix.file_descr list * Unix.file_descr list</CODE><BR><CODE>= &lt;fun&gt;</CODE><BR>

</PRE>

The first three arguments represent lists of respectively
inputs, of outputs and error-outputs. The last argument
indicates a delay in seconds. A negative value means
the null delay. The results are the lists of available
input, output and error-output.<BR>
<BR>


<H3> Warning </H3> <HR>

<TT>select</TT> is not implemented under Windows


<HR>

<BR>
<BR>
<HR>
<A HREF="book-ora165.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora167.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
